'''
待完善：

调试记录:
2024
7.31 --- 完善了下位机传来数据的更新率 下位机DMA传输太快 缓存叠了太多数据 应该缩短每帧数据间处理
8.1 --- 尝试加入数据显示图像 --- 失败
8.2 --- 调整组件位置、加入编码器位置反馈、模拟人类行为等
8月调试：搭搭配最新上位机 程序用原先的 一切正常 不会让陀螺仪输出传输出现问题
用新控制程序 即使屏蔽的执行内容 依旧会出问题 -- 奇怪 -- 待排查
9.3 --- 保持最新GUI不变 重构下位机程序  重构成功
9.4 --- 加入polhemux数据通信
9.5 --- 加入CAN数据反馈
9.11\12 --- 加入电机数据框及脚本文件 是否接收
10.30 --- 加入肌腱控制选择
11.4 --- 加入上位机肌腱气压显示及气压控制、数据解析逻辑调整
11.5 --- 将两字节接收计算改为直接接收四字节浮点数 --- 实际上append作祟 都可以感觉 且100ms最大接收改为200ms最大接收
11.12 -- 将打印polhemux数据去掉 增加数据处理速度
11.25 -- 加入输入气压记录 即脚本完善

2025
3.9 --- 加入稳定数据记录 不用连续数据记录 因蓝牙有延迟 肌腱有滞后 对不上数据
3.24 --- 加入另USB口对IMU数据进行实时接收 顺便开第二线程开启数据接收  AutoFind_Serial.py 已修改
3.25 --- 加入腕部IMU数据解析 并显示在GUI上
3.26 --- 加入100hz频率定时给下位机发送IMU数据
3.31 --- 加入肘部IMU数据解析 同步发送给下位机
'''

import tkinter as tk  # gui相关的库
import threading  # 多线程库
import serial  # 串口通信库

import serial.tools.list_ports
from tkinter import ttk
from tkinter import messagebox  # 提示窗口
from tkinter import scrolledtext  # 与列表相关
from tkinter.constants import END
import time

import struct

import matplotlib.pyplot as plt
from math import *

import AutoFind_Serial

# angle_roll_show = []
# angle_yaw_show = []
# angle_pitch_show = []
# x_show = []
# Init_time = 0

tk_window = tk.Tk()  # 创建窗口
tk_window.title(
    "---------------------------------------------------------------------------Universal GUI(YuanQuan.Dai)-----------------------------------------------------------------------------")  # 窗口标题名称
tk_window.geometry("1500x950+400+130")
tk_window.resizable(True, True)  # 不锁定边框大小
# 串口
serial_place_x = 0
serial_place_y = 0
serial_place_width = 750
serial_place_height = 100
serial_port = serial.Serial()  # 创建串口
Com_Init = 'COM'
Com_List = []
Com_Init_Num = 15

re_data = bytes()
port_tuple = ()
Com_Count = 0
t = [0]
t_now = 0
m = [sin(t_now)]
i = 0
j = 0
target_roll = 0
wait_record_flag = 0

polhemux_data_bias = 38
polhemux_data_len = 60
r_analog = [0]
real_r_voltage = [0]
real_r_trachea = [0]

# 稳定数据记录变量
prev_angle_pitch = 0.0
prev_angle_roll = 0.0
prev_angle_yaw = 0.0
stability_counter = 0
data_recorded_flag = 0  # 0表示未记录，1表示已记录

pressure_callback_bias = 9
MPU_data_len = 43
set_r_pressure_diff = 0.0

def start_imu_thread():
    imu_usb_t = threading.Thread(target=USBIMU_send_serial_rev_threading)
    imu_usb_t.Daemon = True
    imu_usb_t.start()  # 开始线程

def USBIMU_send_serial_rev_threading():
    while serial_port.isOpen():
        try:
            TxData = []
            TxData.append(frame_head)
            TxData.append(0x88)
            #腕部
            acc_x = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.acc_x))
            acc_y = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.acc_y))
            acc_z = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.acc_z))
            gyro_x = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.gyro_x))
            gyro_y = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.gyro_y))
            gyro_z = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.gyro_z))
            pitch = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.pitch))
            roll = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.roll))
            yaw = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.yaw))

            #肘部
            elbow_acc_x = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_acc_x))
            elbow_acc_y = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_acc_y))
            elbow_acc_z = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_acc_z))
            elbow_gyro_x = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_gyro_x))
            elbow_gyro_y = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_gyro_y))
            elbow_gyro_z = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_gyro_z))
            elbow_pitch = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_pitch))
            elbow_roll = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_roll))
            elbow_yaw = struct.unpack('<4B', struct.pack('<f', AutoFind_Serial.elbow_yaw))

            # 气压数据
            set_r_pressure_diff_4b = struct.unpack('<4B', struct.pack('<f', set_r_pressure_diff))

            # 将浮点数拆成四字节无符号数发送 即一个浮点数对应四个字节数据
            ## 腕部 ---> 4 * 9 = 36
            TxData.append(acc_x[0])
            TxData.append(acc_x[1])
            TxData.append(acc_x[2])
            TxData.append(acc_x[3])
            TxData.append(acc_y[0])
            TxData.append(acc_y[1])
            TxData.append(acc_y[2])
            TxData.append(acc_y[3])
            TxData.append(acc_z[0])
            TxData.append(acc_z[1])
            TxData.append(acc_z[2])
            TxData.append(acc_z[3])
            TxData.append(gyro_x[0])
            TxData.append(gyro_x[1])
            TxData.append(gyro_x[2])
            TxData.append(gyro_x[3])
            TxData.append(gyro_y[0])
            TxData.append(gyro_y[1])
            TxData.append(gyro_y[2])
            TxData.append(gyro_y[3])
            TxData.append(gyro_z[0])
            TxData.append(gyro_z[1])
            TxData.append(gyro_z[2])
            TxData.append(gyro_z[3])
            TxData.append(pitch[0])
            TxData.append(pitch[1])
            TxData.append(pitch[2])
            TxData.append(pitch[3])
            TxData.append(roll[0])
            TxData.append(roll[1])
            TxData.append(roll[2])
            TxData.append(roll[3])
            TxData.append(yaw[0])
            TxData.append(yaw[1])
            TxData.append(yaw[2])
            TxData.append(yaw[3])
            ## 肘部 ---> 4 * 9 = 36
            TxData.append(elbow_acc_x[0])
            TxData.append(elbow_acc_x[1])
            TxData.append(elbow_acc_x[2])
            TxData.append(elbow_acc_x[3])
            TxData.append(elbow_acc_y[0])
            TxData.append(elbow_acc_y[1])
            TxData.append(elbow_acc_y[2])
            TxData.append(elbow_acc_y[3])
            TxData.append(elbow_acc_z[0])
            TxData.append(elbow_acc_z[1])
            TxData.append(elbow_acc_z[2])
            TxData.append(elbow_acc_z[3])
            TxData.append(elbow_gyro_x[0])
            TxData.append(elbow_gyro_x[1])
            TxData.append(elbow_gyro_x[2])
            TxData.append(elbow_gyro_x[3])
            TxData.append(elbow_gyro_y[0])
            TxData.append(elbow_gyro_y[1])
            TxData.append(elbow_gyro_y[2])
            TxData.append(elbow_gyro_y[3])
            TxData.append(elbow_gyro_z[0])
            TxData.append(elbow_gyro_z[1])
            TxData.append(elbow_gyro_z[2])
            TxData.append(elbow_gyro_z[3])
            TxData.append(elbow_pitch[0])
            TxData.append(elbow_pitch[1])
            TxData.append(elbow_pitch[2])
            TxData.append(elbow_pitch[3])
            TxData.append(elbow_roll[0])
            TxData.append(elbow_roll[1])
            TxData.append(elbow_roll[2])
            TxData.append(elbow_roll[3])
            TxData.append(elbow_yaw[0])
            TxData.append(elbow_yaw[1])
            TxData.append(elbow_yaw[2])
            TxData.append(elbow_yaw[3])

            # 气压数据
            TxData.append(set_r_pressure_diff_4b[0])
            TxData.append(set_r_pressure_diff_4b[1])
            TxData.append(set_r_pressure_diff_4b[2])
            TxData.append(set_r_pressure_diff_4b[3])

            TxData.append(frame_tail)
            if serial_port.isOpen():
                serial_port.write(TxData)

        except SerialException as e:
            print(f"串口错误: {e}")
            break
        except Exception as e:
            print(f"意外错误: {e}")

        time.sleep(0.05)  # 50ms

def USB_IMUthreading():
    acc_x_entry.configure(state='normal')
    acc_y_entry.configure(state='normal')
    acc_z_entry.configure(state='normal')
    gyro_x_entry.configure(state='normal')
    gyro_y_entry.configure(state='normal')
    gyro_z_entry.configure(state='normal')
    roll_entry.configure(state='normal')
    pitch_entry.configure(state='normal')
    yaw_entry.configure(state='normal')

    acc_x_entry.delete(0, END)
    acc_y_entry.delete(0, END)
    acc_z_entry.delete(0, END)
    gyro_x_entry.delete(0, END)
    gyro_y_entry.delete(0, END)
    gyro_z_entry.delete(0, END)
    roll_entry.delete(0, END)
    pitch_entry.delete(0, END)
    yaw_entry.delete(0, END)

    # 通过USB接收的IMU数据
    acc_x_entry.insert(0, str(AutoFind_Serial.acc_x)[:6])
    acc_y_entry.insert(0, str(AutoFind_Serial.acc_y)[:6])
    acc_z_entry.insert(0, str(AutoFind_Serial.acc_z)[:6])
    gyro_x_entry.insert(0, str(AutoFind_Serial.gyro_x)[:6])
    gyro_y_entry.insert(0, str(AutoFind_Serial.gyro_y)[:6])
    gyro_z_entry.insert(0, str(AutoFind_Serial.gyro_z)[:6])
    pitch_entry.insert(0, str(AutoFind_Serial.pitch)[:6])
    roll_entry.insert(0, str(AutoFind_Serial.roll)[:6])
    yaw_entry.insert(0, str(AutoFind_Serial.yaw)[:6])

def data_deal(data):
    print(len(data))
    global i, j, target_roll, wait_record_flag, prev_angle_pitch, prev_angle_roll, prev_angle_yaw, stability_counter, data_recorded_flag
    
    # if data[0] == 0xAA and data[len(data) - 1] == 0x55 and len(data) >= 132: #含polhemux 60个字节 + 蓝牙IMU 36字节
    if data[0] == 0xAA and data[1] == 0x01 and data[len(data) - 1] == 0x55 and len(data) >= MPU_data_len:
        USB_IMUthreading()
        # 蓝牙IMU
        # r_acc_x = data[2] << 24 | data[3] << 16 | data[4] << 8 | data[5]
        # r_acc_y = data[6] << 24 | data[7] << 16 | data[8] << 8 | data[9]
        # r_acc_z = data[10] << 24 | data[11] << 16 | data[12] << 8 | data[13]
        # r_gyro_x = data[14] << 24 | data[15] << 16 | data[16] << 8 | data[17]
        # r_gyro_y = data[18] << 24 | data[19] << 16 | data[20] << 8 | data[21]
        # r_gyro_z = data[22] << 24 | data[23] << 16 | data[24] << 8 | data[25]
        # r_angle_pitch = data[26] << 24 | data[27] << 16 | data[28] << 8 | data[29]
        # r_angle_roll = data[30] << 24 | data[31] << 16 | data[32] << 8 | data[33]
        # r_angle_yaw = data[34] << 24 | data[35] << 16 | data[36] << 8 | data[37]
        #
        # r_acc_x = struct.unpack('<f', struct.pack('<I', r_acc_x))
        # r_acc_y = struct.unpack('<f', struct.pack('<I', r_acc_y))
        # r_acc_z = struct.unpack('<f', struct.pack('<I', r_acc_z))
        # r_gyro_x = struct.unpack('<f', struct.pack('<I', r_gyro_x))
        # r_gyro_y = struct.unpack('<f', struct.pack('<I', r_gyro_y))
        # r_gyro_z = struct.unpack('<f', struct.pack('<I', r_gyro_z))
        # r_angle_roll = struct.unpack('<f', struct.pack('<I', r_angle_roll))
        # r_angle_pitch = struct.unpack('<f', struct.pack('<I', r_angle_pitch))
        # r_angle_yaw = struct.unpack('<f', struct.pack('<I', r_angle_yaw))

        # 单片机通过蓝牙接收的IMU数据
        # acc_x_entry.insert(0, str(r_acc_x)[1:6])
        # acc_y_entry.insert(0, str(r_acc_y)[1:6])
        # acc_z_entry.insert(0, str(r_acc_z)[1:6])
        # gyro_x_entry.insert(0, str(r_gyro_x)[1:6])
        # gyro_y_entry.insert(0, str(r_gyro_y)[1:6])
        # gyro_z_entry.insert(0, str(r_gyro_z)[1:6])
        # pitch_entry.insert(0, str(r_angle_pitch)[1:6])
        # roll_entry.insert(0, str(r_angle_roll)[1:6])
        # yaw_entry.insert(0, str(r_angle_yaw)[1:6])

        # polhemux数据整合
        # if data[0 + polhemux_data_bias] == 48 and data[1 + polhemux_data_bias] == 52 and data[58 + polhemux_data_bias] == 13 and data[59 + polhemux_data_bias] == 10: #data是字节型数据 为整数 '0' '4' 0D 0A
        #     # 输出框中打印接收
        #     # rev_buffer_scr.insert(END, data[polhemux_data_bias:polhemux_data_bias + polhemux_data_len])
        #     # rev_buffer_scr.insert(END, '\n')
        #     # rev_buffer_scr.see(END)
        #     polhemux_sensor_rev = data[38:98].split()
        #     # print(len(polhemux_sensor_rev))
        #
        #     if len(polhemux_sensor_rev) < 8: # 脏数据处理 长度大于=8 的数据丢掉
        #         polhemux_sensor1_x_entry.configure(state='normal')
        #         polhemux_sensor1_y_entry.configure(state='normal')
        #         polhemux_sensor1_z_entry.configure(state='normal')
        #         polhemux_sensor1_yaw_entry.configure(state='normal')
        #         polhemux_sensor1_pitch_entry.configure(state='normal')
        #         polhemux_sensor1_roll_entry.configure(state='normal')
        #
        #         polhemux_sensor1_x_entry.delete(0, END)
        #         polhemux_sensor1_y_entry.delete(0, END)
        #         polhemux_sensor1_z_entry.delete(0, END)
        #         polhemux_sensor1_yaw_entry.delete(0, END)
        #         polhemux_sensor1_pitch_entry.delete(0, END)
        #         polhemux_sensor1_roll_entry.delete(0, END)
        #
        #         r_sensor1_x = polhemux_sensor_rev[1].decode('utf-8') # types 转 str
        #         r_sensor1_y = polhemux_sensor_rev[2].decode('utf-8')
        #         r_sensor1_z = polhemux_sensor_rev[3].decode('utf-8')
        #         r_sensor1_yaw = polhemux_sensor_rev[4].decode('utf-8')
        #         r_sensor1_pitch = polhemux_sensor_rev[5].decode('utf-8')
        #         r_sensor1_roll = polhemux_sensor_rev[6].decode('utf-8')
        #
        #
        #         polhemux_sensor1_x_entry.insert(0, r_sensor1_x)
        #         polhemux_sensor1_y_entry.insert(0, r_sensor1_y)
        #         polhemux_sensor1_z_entry.insert(0, r_sensor1_z)
        #         polhemux_sensor1_yaw_entry.insert(0, r_sensor1_yaw)
        #         polhemux_sensor1_pitch_entry.insert(0, r_sensor1_pitch)
        #         polhemux_sensor1_roll_entry.insert(0, r_sensor1_roll)

        # 关节角整合
        # Joint1_real_callback_ang = data[98] << 24 | data[99] << 16 | data[100] << 8 | data[101]
        # Joint2_real_callback_ang = data[102] << 24 | data[103] << 16 | data[104] << 8 | data[105] #含polhemux和蓝牙IMU
        Joint1_real_callback_ang = data[2] << 24 | data[3] << 16 | data[4] << 8 | data[5]
        Joint2_real_callback_ang = data[6] << 24 | data[7] << 16 | data[8] << 8 | data[9]
        Joint1_real_callback_ang = struct.unpack('<f', struct.pack('<I', Joint1_real_callback_ang))
        Joint2_real_callback_ang = struct.unpack('<f', struct.pack('<I', Joint2_real_callback_ang))

        Joint_Motor_ID1_entry.configure(state='normal')
        Joint_Motor_ID2_entry.configure(state='normal')

        Joint_Motor_ID1_entry.delete(0, END)
        Joint_Motor_ID2_entry.delete(0, END)

        Joint1_real_ang = str(Joint1_real_callback_ang)[1:9]
        Joint2_real_ang = str(Joint2_real_callback_ang)[1:9]

        Joint_Motor_ID1_entry.insert(0, Joint1_real_ang)
        Joint_Motor_ID2_entry.insert(0, Joint2_real_ang)

        real_r_trachea_1 = data[pressure_callback_bias + 1] << 24 | data[pressure_callback_bias + 2] << 16 | data[pressure_callback_bias + 3] << 8 | data[pressure_callback_bias + 4]
        real_r_trachea_2 = data[pressure_callback_bias + 5] << 24 | data[pressure_callback_bias + 6] << 16 | data[pressure_callback_bias + 7] << 8 | data[pressure_callback_bias + 8]
        real_r_trachea_3 = data[pressure_callback_bias + 9] << 24 | data[pressure_callback_bias + 10] << 16 | data[pressure_callback_bias + 11] << 8 | data[pressure_callback_bias + 12]
        real_r_trachea_4 = data[pressure_callback_bias + 13] << 24 | data[pressure_callback_bias + 14] << 16 | data[pressure_callback_bias + 15] << 8 | data[pressure_callback_bias + 16]
        real_r_trachea_5 = data[pressure_callback_bias + 17] << 24 | data[pressure_callback_bias + 18] << 16 | data[pressure_callback_bias + 19] << 8 | data[pressure_callback_bias + 20]
        real_r_trachea_6 = data[pressure_callback_bias + 21] << 24 | data[pressure_callback_bias + 22] << 16 | data[pressure_callback_bias + 23] << 8 | data[pressure_callback_bias + 24]
        real_r_trachea_7 = data[pressure_callback_bias + 25] << 24 | data[pressure_callback_bias + 26] << 16 | data[pressure_callback_bias + 27] << 8 | data[pressure_callback_bias + 28]

        real_r_trachea_1 = struct.unpack('<f', struct.pack('<I', real_r_trachea_1))
        real_r_trachea_2 = struct.unpack('<f', struct.pack('<I', real_r_trachea_2))
        real_r_trachea_3 = struct.unpack('<f', struct.pack('<I', real_r_trachea_3))
        real_r_trachea_4 = struct.unpack('<f', struct.pack('<I', real_r_trachea_4))
        real_r_trachea_5 = struct.unpack('<f', struct.pack('<I', real_r_trachea_5))
        real_r_trachea_6 = struct.unpack('<f', struct.pack('<I', real_r_trachea_6))
        real_r_trachea_7 = struct.unpack('<f', struct.pack('<I', real_r_trachea_7))

        prev_target_roll = target_roll
        target_roll = data[pressure_callback_bias + 29] << 24 | data[pressure_callback_bias + 30] << 16 | data[pressure_callback_bias + 31] << 8 | data[pressure_callback_bias + 32]
        target_roll = struct.unpack('<f', struct.pack('<I', target_roll))
        if prev_target_roll != target_roll: #来新的期望角
            wait_record_flag = 1
            stability_counter = 0

        # 计算能力不够 无法短时间内实时计算
        # r_analog.append(data[105 + 2] << 8 | data[105 + 1])
        # r_analog.append(data[105 + 4] << 8 | data[105 + 3])
        # r_analog.append(data[105 + 6] << 8 | data[105 + 5])
        # r_analog.append(data[105 + 8] << 8 | data[105 + 7])
        # r_analog.append(data[105 + 10] << 8 | data[105 + 9])
        # r_analog.append(data[105 + 12] << 8 | data[105 + 11])
        # r_analog.append(data[105 + 14] << 8 | data[105 + 13])

        # real_r_voltage.append(r_analog[1] / 4096.0 * 3.3)
        # real_r_voltage.append(r_analog[2] / 4096.0 * 3.3)
        # real_r_voltage.append(0)
        # real_r_voltage.append(r_analog[4] / 4096.0 * 3.3)
        # real_r_voltage.append(r_analog[5] / 4096.0 * 3.3)
        # real_r_voltage.append(r_analog[6] / 4096.0 * 3.3)
        # real_r_voltage.append(r_analog[7] / 4096.0 * 3.3)
        # print(real_r_voltage)
        #
        # real_r_trachea.append(real_r_voltage[1] / 3.3 * 10.0)
        # real_r_trachea.append(real_r_voltage[2] / 3.3 * 10.0)
        # real_r_trachea.append(0)
        # real_r_trachea.append(real_r_voltage[4] / 3.3 * 10.0)
        # real_r_trachea.append(real_r_voltage[5] / 3.3 * 10.0)
        # real_r_trachea.append(real_r_voltage[6] / 3.3 * 10.0)
        # real_r_trachea.append(real_r_voltage[7] / 3.3 * 10.0)

        ppv_1_entry.configure(state='normal')
        ppv_2_entry.configure(state='normal')
        ppv_3_entry.configure(state='normal')
        ppv_4_entry.configure(state='normal')
        ppv_5_entry.configure(state='normal')
        ppv_6_entry.configure(state='normal')
        ppv_7_entry.configure(state='normal')

        ppv_1_entry.delete(0, END)
        ppv_2_entry.delete(0, END)
        ppv_3_entry.delete(0, END)
        ppv_4_entry.delete(0, END)
        ppv_5_entry.delete(0, END)
        ppv_6_entry.delete(0, END)
        ppv_7_entry.delete(0, END)

        ppv_1_entry.insert(0, str(real_r_trachea_1[0])[:5])
        ppv_2_entry.insert(0, str(real_r_trachea_2[0])[:5])
        ppv_3_entry.insert(0, str(real_r_trachea_3[0])[:5])
        ppv_4_entry.insert(0, str(real_r_trachea_4[0])[:5])
        ppv_5_entry.insert(0, str(real_r_trachea_5[0])[:5])
        ppv_6_entry.insert(0, str(real_r_trachea_6[0])[:5])
        ppv_7_entry.insert(0, str(real_r_trachea_7[0])[:5])

        # 稳定数据记录功能
        if Motor_record_state.get() == 1:
            # 检查角度是否稳定
            angle_pitch_diff = abs(AutoFind_Serial.pitch - prev_angle_pitch)
            angle_roll_diff = abs(AutoFind_Serial.roll - prev_angle_roll)
            angle_yaw_diff = abs(AutoFind_Serial.yaw - prev_angle_yaw)

            # 检查稳定性条件
            if angle_pitch_diff < 0.05 and angle_roll_diff < 0.05 and angle_yaw_diff < 0.05 and wait_record_flag == 1:
                stability_counter += 1
            else:
                stability_counter = 0

            # 当稳定计数达到15且标志位为0时，记录数据
            # if stability_counter >= 20 and data_recorded_flag == 0 :
            if stability_counter >= 200 and wait_record_flag == 1:
                with open("wrist_stable_data_record.log", 'a', encoding='utf-8') as f:
                    local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
                    f.write('============================\n')
                    Debug_Content = '%s-->第%d次稳定数据采集-->real_r_trachea_1:%sbar real_r_trachea_2:%sbar real_r_trachea_3:%sbar real_r_trachea_4:%sbar real_r_trachea_5:%sbar real_r_trachea_6:%sbar real_r_trachea_7:%sbar r_angle_roll:%s° r_angle_pitch:%s° r_angle_yaw:%s° target_roll:%s°' % (
                        local_time, j + 1, str(real_r_trachea_1[0])[:5], str(real_r_trachea_2[0])[:5], str(real_r_trachea_3[0])[:5],
                        str(real_r_trachea_4[0])[:5], str(real_r_trachea_5[0])[:5], str(real_r_trachea_6[0])[:5],
                        str(real_r_trachea_7[0])[:5], str(AutoFind_Serial.roll)[:6], str(AutoFind_Serial.pitch)[:6], str(AutoFind_Serial.yaw)[:6], str(target_roll)[1:6])
                    f.write(Debug_Content + '\n')
                    j = j + 1

                # # 设置标志位，表示当前稳定状态已记录
                # data_recorded_flag = 1
                wait_record_flag = 0

                # 显示稳定状态记录提示
                rev_buffer_scr.insert(END, "已记录稳定状态数据！\n")
                rev_buffer_scr.see(END)

            # 保存当前角度值作为下一次比较的基准
            prev_angle_pitch = AutoFind_Serial.pitch
            prev_angle_roll = AutoFind_Serial.roll
            prev_angle_yaw = AutoFind_Serial.yaw

            
            # 也保留原来的连续记录功能
            with open("wrist_data_record.log", 'a', encoding='utf-8') as f:
                local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
                f.write('============================')
                f.write('\n')
                Debug_Content = '%s-->第%d次采集-->real_r_trachea_1:%sbar real_r_trachea_2:%sbar real_r_trachea_3:%sbar real_r_trachea_4:%sbar real_r_trachea_5:%sbar real_r_trachea_6:%sbar real_r_trachea_7:%sbar r_angle_roll:%s° r_angle_pitch:%s° r_angle_yaw:%s° target_roll:%s°' % (
                    local_time, i + 1, str(real_r_trachea_1[0])[:5], str(real_r_trachea_2[0])[:5], str(real_r_trachea_3[0])[:5], str(real_r_trachea_4[0])[:5], str(real_r_trachea_5[0])[:5], str(real_r_trachea_6[0])[:5], str(real_r_trachea_7[0])[:5], str(AutoFind_Serial.roll)[:6], str(AutoFind_Serial.pitch)[:6], str(AutoFind_Serial.yaw)[:6], str(target_roll)[1:6])
                f.write(Debug_Content)
                f.write('\n')
            i = i + 1

from serial import SerialException

def serial_rev_threading():
    print('串口接收线程启动')
    buffer = bytearray()  # 数据缓冲区
    frame_len = MPU_data_len        # 每帧数据长度
    HEADER = 0xAA         # 帧头
    FOOTER = 0x55         # 帧尾
    
    while serial_port.isOpen():
        try:
            # 1. 非阻塞读取所有可用数据
            waiting = serial_port.in_waiting
            if waiting > 0:
                buffer += serial_port.read(waiting)
                print(len(buffer))
            
            # 2. 处理完整数据帧
            while len(buffer) >= frame_len:
                # 查找有效帧头帧尾组合
                start_pos = -1
                for i in range(len(buffer) - frame_len + 1):
                    if buffer[i] == HEADER and buffer[i + frame_len - 1] == FOOTER:
                        start_pos = i
                        break

                # 未找到有效帧
                if start_pos == -1:
                    buffer.clear()
                    break
                
                # 找到完整帧
                frame = buffer[start_pos:start_pos+frame_len]
                buffer = buffer[start_pos+frame_len:]  # 移除已处理数据
                data_deal(frame)  # 调用你的数据处理函数

            
            # 3. 控制处理频率（适配10Hz）
            time.sleep(0.005)  # 5ms延迟（略小于10ms周期）

            # if re_data:
            #     if rev_state.get() == 0:
            #         if rev_encode_list.get() == 'UTF-8':
            #             Ans_Data = re_data.decode('UTF-8')
            #         elif rev_encode_list.get() == 'GB2312':
            #             Ans_Data = re_data.decode('GB2312')

            #     elif rev_state.get() == 1:
            #         Ans_Data = re_data.hex()
            
        except SerialException as e:
            print(f"串口错误: {e}")
            break
        except Exception as e:
            print(f"处理错误: {e}")
            buffer.clear()  # 清空缓冲区

    print('串口接收线程退出')

##############################单片机串口线程函数#################################

def com_create(num):
    for i in range(0, num):
        Com_List.append(Com_Init + str(i))
    print(Com_List)
    return Com_List


def crc_data_update():
    if crc_list.get() == '无':
        crc_get = 'N'  # NONE
    elif crc_list.get() == '奇效验':
        crc_get = 'O'  # ODD
    elif crc_list.get() == '偶效验':
        crc_get = 'E'  # EVEN

    return crc_get


###########################打开串口#################################
def open_serial():
    if not serial_port.isOpen():
        serial_port.port = port_list.get()  # 列表获取串口号
        serial_port.baudrate = baudrate_list.get()  # 列表获取波特率
        serial_port.bytesize = eval(data_bit_list.get())  # 列表获取数据位数
        serial_port.parity = crc_data_update()  # crc_list.get() #列表获取奇偶效验
        serial_port.stopbits = eval(stop_bit_list.get())  # 列表获取停止位数
        serial_port.timeout = 1
        serial_port.open()  # 打开串口
        messagebox.showinfo("通信", "连接成功")  # 窗口提示
        if serial_port.isOpen():
            messagebox.showinfo("通信", "打开串口成功")  # 窗口提示
            serial_t = threading.Thread(target=serial_rev_threading)
            serial_t.Daemon = True
            serial_t.start()  # 开始线程
            # 如果放主函数 会导致该线程占用太多 连上位机界面的串口都打开不了
            start_imu_thread()

        else:
            messagebox.showinfo("通信", "打开串口失败")  # 窗口提示
            serial_port.close()


#########################关闭串口###################################
def close_serial():
    if serial_port.isOpen():
        serial_port.close()
        messagebox.showinfo("通信", "连接断开")


####################################################################
####################################################################
####################################################################
############################ 串口配置区域 ############################
####################################################################
####################################################################
####################################################################
serial_local = tk.LabelFrame(tk_window,  # 区域所在窗口
                             text="串口配置",  # 这片区域的名称
                             bg="white",  # 区域背景色
                             fg="black",  # 前景色
                             padx=10,
                             pady=10
                             )  # Frame可以确定一片区域 450 50 230 300
serial_local.place(x=serial_place_x, y=serial_place_y,
                   width=serial_place_width, height=serial_place_height
                   )  # x y越小越趋向与左上角

################### 文本显示  place的xy是和普通的直角坐标对应的 ###########
serial_conf_label_column_step = 2
serial_conf_label_row_step = 2
tk.Label(serial_local,
         text="端口:",
         bg="white",
         fg="black").grid(column=serial_conf_label_column_step*0, row=serial_conf_label_row_step*0)
tk.Label(serial_local,
         text="波特率:",
         bg="white",
         fg="black").grid(column=serial_conf_label_column_step*1, row=serial_conf_label_row_step*0)
tk.Label(serial_local,
         text="数据位:",
         bg="white",
         fg="black").grid(column=serial_conf_label_column_step*2, row=serial_conf_label_row_step*0)
tk.Label(serial_local,
         text="效验位:",
         bg="white",
         fg="black").grid(column=serial_conf_label_column_step*3, row=serial_conf_label_row_step*0)
tk.Label(serial_local,
         text="停止位:",
         bg="white",
         fg="black").grid(column=serial_conf_label_column_step*4, row=serial_conf_label_row_step*0)
tk.Label(serial_local,
         text="发送编:",
         bg="white",
         fg="black").grid(column=serial_conf_label_column_step*0, row=serial_conf_label_row_step*1)
tk.Label(serial_local,
         text="接收编:",
         bg="white",
         fg="black").grid(column=serial_conf_label_column_step*1, row=serial_conf_label_row_step*1)

####################################串口更新线程函数##########################################
com_list_width = 7
Com_Count = 0
def Com_Refresh_threading():
    global Com_Count, port_list
    while True:
        port_list['values'] = port_tuple
        port_list.grid(column=serial_conf_label_column_step*0+1, row=serial_conf_label_row_step*0)
        time.sleep(5)

####################################下拉列表##########################################

port = tk.StringVar()  # 端口字符串 StringVar--定义可变参数
port_list = ttk.Combobox(serial_local,  # Combobox--组合框
                         width=com_list_width,
                         textvariable=port,
                         )
port_list['value'] = ('COM1',
                      'COM2',
                      'COM3',
                      'COM4',
                      'COM5',
                      'COM6',
                      'COM7')
port_list.current(3)
port_list.grid(column=serial_conf_label_column_step*0+1, row=serial_conf_label_row_step*0)


# 下拉列表
baudrate = tk.StringVar()  # 波特率字符串
baudrate_list = ttk.Combobox(serial_local,
                             width=com_list_width,
                             textvariable=baudrate,
                             state='readonly')
baudrate_list['values'] = (1200,
                           2400,
                           4800,
                           9600,
                           14400,
                           19200,
                           38400,
                           43000,
                           57600,
                           76800,
                           115200,
                           460800)
baudrate_list.current(11)  # 初始显示
baudrate_list.grid(column=serial_conf_label_column_step*1+1, row=serial_conf_label_row_step*0)

# 下拉列表
data_bit = tk.StringVar()  # 数据位宽度字符串
data_bit_list = ttk.Combobox(serial_local,
                             width=com_list_width,  # 列表的宽度与数据无关
                             textvariable=data_bit,
                             state='readonly')
data_bit_list['values'] = (5,
                           6,
                           7,
                           8)
data_bit_list.current(3)  # 初始显示
data_bit_list.grid(column=serial_conf_label_column_step*2+1, row=serial_conf_label_row_step*0)

# 下拉列表
crc = tk.StringVar()  # 校验位字符串
crc_list = ttk.Combobox(serial_local,
                        width=com_list_width,
                        textvariable=crc,
                        state='readonly')
crc_list['values'] = ('无',
                      '奇效验',
                      '偶效验')
crc_list.current(0)  # 初始显示
crc_list.grid(column=serial_conf_label_column_step*3+1, row=serial_conf_label_row_step*0)

# 下拉列表
stop_bit = tk.StringVar()  # 停止位字符串
stop_bit_list = ttk.Combobox(serial_local,
                             width=com_list_width,
                             textvariable=stop_bit,
                             state='readonly')
stop_bit_list['values'] = (1,
                           1.5,
                           2)
stop_bit_list.current(0)  # 初始显示
stop_bit_list.grid(column=serial_conf_label_column_step*4+1, row=serial_conf_label_row_step*0)

# 发送端编码格式
send_encode = tk.StringVar()
send_encode_list = ttk.Combobox(serial_local,
                             width=com_list_width,
                             textvariable=send_encode,
                             state='readonly')
send_encode_list['value'] = ('UTF-8', 'GB2312')
send_encode_list.current(0)
send_encode_list.grid(column=serial_conf_label_column_step*0+1, row=serial_conf_label_row_step*1)

# 接收端编码格式
rev_encode = tk.StringVar()
rev_encode_list = ttk.Combobox(serial_local,
                             width=com_list_width,
                             textvariable=rev_encode,
                             state='readonly')
rev_encode_list['value'] = ('UTF-8', 'GB2312')
rev_encode_list.current(0)
rev_encode_list.grid(column=serial_conf_label_column_step*1+1, row=serial_conf_label_row_step*1)

# 按键
tk.Button(serial_local,
          text="打开串口",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体背景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=open_serial,  # 不能写成command = open_serial()不然按键不会按也会执行 （猜：若写成open_serial()必须前面加lamda：）
          ).grid(column=serial_conf_label_column_step*5+1, row=serial_conf_label_row_step*0)
# 按键
tk.Button(serial_local,
          text="关闭串口",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体背景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=close_serial
          ).grid(column=serial_conf_label_column_step*6+1, row=serial_conf_label_row_step*0)


####################################################################
####################################################################
####################################################################
########################### 串口发送数据区域 ##########################
####################################################################
####################################################################
####################################################################
def Ser_Send(cmd):
    if serial_port.isOpen():
        if sent_state.get() == 1:
            serial_port.write(bytes.fromhex(cmd))
        elif sent_state.get() == 0:
            serial_port.write(cmd)

serial_sent = tk.LabelFrame(tk_window,  # 区域所在窗口
                                text="发送数据区域",  # 这片区域的名称
                                bg="white",  # 区域背景色
                                fg="black",  # 前景色
                                padx=10,
                                pady=10
                                )
serial_sent.place(x=serial_place_x, y=serial_place_y + serial_place_height,
                      width=serial_place_width, height=serial_place_height * 2
                      )  # x y越小越趋向与左上角

TX_Frame = tk.Entry(serial_sent,
                        width=10,
                        highlightcolor='black',
                        highlightthickness=1)
TX_Frame.place(x=0, y=0, width=serial_place_width - 100, height=serial_place_height * 1.5)
TX_Frame.insert(0, '')

# 按键 flat, groove, raised, ridge, solid, or sunken
tk.Button(serial_sent,
          text="发送",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(sent_state.get()),
          ).place(x=serial_place_width - 95, y=0, width=80, height=30)

# 是否HEX发送复选框
sent_state = tk.IntVar()
s_state = tk.Checkbutton(serial_sent, text = "hex发送", variable = sent_state, bg="white",  fg="black")
s_state.select()
s_state.place(x=serial_place_width - 95, y=40, width=80, height=30)

####################################################################
####################################################################
####################################################################
############################ AT指令可选区域 ##########################
####################################################################
####################################################################
####################################################################
AT_Ins_Dict = {'typeC': 'AT+GPIO=?',
               'Arduino&GPIO': 'AT+GPIO=0:2:0:0',  # 0.02管脚 输入 低电平
               'Grove4PIN_UART': 'AT+UART',
               'Grove4PIN_ADC': 'AT+ADC=?',
               'Grove4PIN_I2C': 'AT+IIC=?',
               'LoRa_TX': 'AT+TTONE',
               'LoRa_RX': 'AT+TRSSI',
               'WIFI': 'AT+WIFIINFO=?',
               'Bluetooth': 'AT+BDMAC=?',
               'GNSS': 'AT+GPSINFO=?',
               'Sensor_PWR,LNA_CTL': 'AT+VSEN=?',
               'BTN': 'BTN',
               'FW_Burn': 'FW_Burn',
               'AAA_battery': 'AAA_battery',
               }
AT_X_Init = 15
AT_Y_Init = 15
AT_X_Step = 120
AT_Y_Step = 60

serial_AT = tk.LabelFrame(tk_window,  # 区域所在窗口
                          text="AT指令可选区域",  # 这片区域的名称
                          bg="white",  # 区域背景色
                          fg="black",  # 前景色
                          padx=10,
                          pady=10
                          )
serial_AT.place(x=serial_place_x, y=serial_place_y + serial_place_height * 3,
                width=serial_place_width, height=serial_place_height * 3
                )


##########################################################写好的AT函数区域############################################################
############## TypeC 接口通信测试 ####################
tk.Button(serial_AT,
          text="TypeC口通信",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('typeC')),  # 传函带参特殊处理
          ).place(x=AT_X_Init + AT_X_Step * 0, y=AT_Y_Init, width=100, height=30)
############## Arduino 兼容 GPIO 接口测试 ####################
tk.Button(serial_AT,
          text=" Arduino&GPIO",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('Arduino&GPIO')),
          ).place(x=AT_X_Init + AT_X_Step * 1, y=AT_Y_Init + AT_Y_Step * 0, width=100, height=30)
##############  Grove 4pin UART 接口测试 ####################
tk.Button(serial_AT,
          text=" Grove 4pin UART",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('Grove4PIN_UART')),
          ).place(x=AT_X_Init + AT_X_Step * 2, y=AT_Y_Init + AT_Y_Step * 0, width=100, height=30)
############## Grove 4pin ADC 采样检测 ####################
tk.Button(serial_AT,
          text="Grove 4pin ADC",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('Grove4PIN_ADC')),
          ).place(x=AT_X_Init + AT_X_Step * 3, y=AT_Y_Init + AT_Y_Step * 0, width=100, height=30)
############## Grove 4pin I2C 设备检测 ####################
tk.Button(serial_AT,
          text="Grove 4pin I2C",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('Grove4PIN_I2C')),
          ).place(x=AT_X_Init + AT_X_Step * 4, y=AT_Y_Init + AT_Y_Step * 0, width=100, height=30)
#################### LoRa 测试 TX发射 ####################
tk.Button(serial_AT,
          text="LoRa_TX",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('LoRa_TX')),
          ).place(x=AT_X_Init + AT_X_Step * 0, y=AT_Y_Init + AT_Y_Step * 1, width=100, height=30)
#################### LoRa 测试 RX接收 ####################
tk.Button(serial_AT,
          text="LoRa_RX",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('LoRa_RX')),
          ).place(x=AT_X_Init + AT_X_Step * 1, y=AT_Y_Init + AT_Y_Step * 1, width=100, height=30)
############## Wi-Fi_信号测试 ####################
tk.Button(serial_AT,
          text="Wi-Fi",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('WIFI')),
          ).place(x=AT_X_Init + AT_X_Step * 2, y=AT_Y_Init + AT_Y_Step * 1, width=100, height=30)
############## BLUE_信号测试 ####################
tk.Button(serial_AT,
          text="Bluetooth",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('Bluetooth')),
          ).place(x=AT_X_Init + AT_X_Step * 3, y=AT_Y_Init + AT_Y_Step * 1, width=100, height=30)
############## GNSS_信号测试 ####################
tk.Button(serial_AT,
          text="GNSS",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('GNSS')),
          ).place(x=AT_X_Init + AT_X_Step * 4, y=AT_Y_Init + AT_Y_Step * 1, width=100, height=30)
############## Sensor_PWR,LNA_CTL 测试 ####################
tk.Button(serial_AT,
          text="Sensor_PWR,LNA_CTL",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('Sensor_PWR,LNA_CTL')),
          ).place(x=AT_X_Init + AT_X_Step * 0, y=AT_Y_Init + AT_Y_Step * 2, width=100, height=30)
############## BTN 按键测试 ####################
tk.Button(serial_AT,
          text="BTN",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('BTN')),
          ).place(x=AT_X_Init + AT_X_Step * 1, y=AT_Y_Init + AT_Y_Step * 2, width=100, height=30)
############## 远程烧录固件测试 ####################
tk.Button(serial_AT,
          text="远程烧录固件",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('FW_Burn')),
          ).place(x=AT_X_Init + AT_X_Step * 2, y=AT_Y_Init + AT_Y_Step * 2, width=100, height=30)
############## AAA*3 电池供电测试 ####################
tk.Button(serial_AT,
          text=" AAA*3",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: Ser_Send(AT_Ins_Dict.get('AAA_battery')),
          ).place(x=AT_X_Init + AT_X_Step * 3, y=AT_Y_Init + AT_Y_Step * 2, width=100, height=30)


####################################################################
####################################################################
####################################################################
############################ 电机指令可选区域 #########################
####################################################################
####################################################################
####################################################################

Motor_Ins_Dict = {
               'RMD_Write_PID_RAM_Command': '0x31',
               'RMD_Write_PID_ROM_Command': '0x32',
               'RMD_Write_Acc_RAM_Command': '0x34',
               'RMD_Write_Encoder_ROM_Calibrate_Zero_Command': '0x91',
               'RMD_Write_Pos_ROM_Calibrate_Zero_Command': '0x19',
               'RMD_Set_Motor_Inital_Pos_Command': '0x95',
               'RMD_Stop_Motor_Command': '0x80',
               'RMD_Pause_Motor_Command': '0x81',
               'RMD_Run_Motor_Command': '0x88',
               'RMD_Torque_Closed_Loop_Control_Command': '0xA1',
               'RMD_Speed_Closed_Loop_Control_Command': '0xA2',
               'RMD_Pos_Closed_Loop_Control_Command_1': '0xA3',
               'RMD_Pos_Closed_Loop_Control_Command_2': '0xA4',
               'RMD_Pos_Closed_Loop_Control_Command_3': '0xA5',
               'RMD_Pos_Closed_Loop_Control_Command_4': '0xA6',
               'RMD_Pos_Closed_Loop_Control_Command_5': '0xA7',
               'RMD_Pos_Closed_Loop_Control_Command_6': '0xA8',

                #joint Five
               'Joint_Set_Pos_Model_Pos_Angle_Command': '0x1E',
               'Joint_Set_Max_Positive_Pos_Command': '0x26',
               'Joint_Set_Min_Negative_Pos_Command': '0x27',
               'Joint_Set_Pos_Bias': '0x53',

               #joint Single
               'Joint_Clear_Err_Command': '0x0B',
               'Set_Joint_Stop': '0x02',
               'Get_Run_State': '0x03',
               'Get_Err_State': '0x0A',
               'Get_M_Now_Pos': '0x08',
               'Get_M_Exp_Pos': '0x09',
               'Get_Pos_Bias': '0x54',

               'Reset_Motor': '0xB0',
               'Forward_90_Command': '0xB1',
               'Turn_Right_90_Command': '0xB2',
               'Inclined_Top_90_Command': '0xB3',
               'Wave_Hand': '0xB4',
               'Draw_Triangular': '0xB5',
               'Draw_circle': '0xB6',
               'Write_on_the_blackboard': '0xB7',
               }
tendon_Dict = {
                'tendon_control_Command': '0x01',
                'tendon_abandon_Command': '0x00',
}
Motor_X_Init = 15
Motor_Y_Init = 15
Motor_X_Step = 120
Motor_Y_Step = 60

serial_Motor = tk.LabelFrame(tk_window,  # 区域所在窗口
                          text="电机指令可选区域",  # 这片区域的名称
                          bg="white",  # 区域背景色
                          fg="black",  # 前景色
                          padx=10,
                          pady=10
                          )
serial_Motor.place(x=serial_place_x, y=serial_place_y + serial_place_height * 6,
                width=serial_place_width, height=serial_place_height * 4
                )

RMD_Motor = 0x01
Joint_Motor = 0x02
Mix_Motor = 0x03
Joint1_ID = 0x01
Joint2_ID = 0x02
frame_head = 0xAA
frame_tail = 0x55
Ctr_Host_Choose = 0x99
tendon_Choose_CMD = 0x04
##脉塔电机控制函数
def RMD_Motor_ins_Send(motor_ID, cmd):
    if HWT901_or_PC_Ctr_list.get() == 'PC':
        TxData = []
        TxData.append(frame_head)
        TxData.append(RMD_Motor)
        TxData.append(eval(Motor_Ins_Dict.get(cmd)))
        TxData.append(eval(motor_ID))
        TxData.append(frame_tail)
        if serial_port.isOpen():
            serial_port.write(TxData)


def RMD_Motor_Single_Pos_Ctr(Motor_ID, ang):
    if HWT901_or_PC_Ctr_list.get() == 'PC':
        TxData = []
        TxData.append(frame_head)
        TxData.append(RMD_Motor)
        TxData.append(eval(Motor_Ins_Dict.get('RMD_Pos_Closed_Loop_Control_Command_2')))
        TxData.append(eval(Motor_ID))
        ang_int = eval(ang)
        #绝对角度控制
        if ang_int >= 360:
            ang_int = 360
        elif ang_int <= 0:
            ang_int = 0
        ang_low_8bit = ang_int & 0xFF
        ang_high_8bit = ang_int >> 8 & 0xFF
        TxData.append(ang_high_8bit)
        TxData.append(ang_low_8bit)
        TxData.append(frame_tail)
        if serial_port.isOpen():
            serial_port.write(TxData)

##关节电机控制函数
def Joint_Motor_Pos_Ctr(Motor_ID, ang):
    if HWT901_or_PC_Ctr_list.get() == 'PC':
        TxData = []
        TxData.append(frame_head)
        TxData.append(Joint_Motor)
        TxData.append(eval(Motor_Ins_Dict.get('Joint_Set_Pos_Model_Pos_Angle_Command')))
        TxData.append(eval(Motor_ID))
        ang_int = eval(ang)
        if eval(Motor_ID) == Joint1_ID:
            if ang_int >= 360:
                ang_int = 360
            elif ang_int <= 1:
                ang_int = 1
        elif eval(Motor_ID) == Joint2_ID:
            if ang_int >= 190:
                ang_int = 190
            elif ang_int <= 1:
                ang_int = 1
        ang_low_8bit = ang_int & 0xFF
        ang_high_8bit = ang_int >> 8 & 0xFF
        TxData.append(ang_high_8bit)
        TxData.append(ang_low_8bit)
        TxData.append(frame_tail)
        if serial_port.isOpen():
            serial_port.write(TxData)

def Joint_Ctr_Single_Cmd_Send(Motor_ID, cmd):
    if HWT901_or_PC_Ctr_list.get() == 'PC':
        TxData = []
        TxData.append(frame_head)
        TxData.append(Joint_Motor)
        TxData.append(eval(Motor_Ins_Dict.get(cmd)))
        TxData.append(eval(Motor_ID))
        TxData.append(frame_tail)
        if serial_port.isOpen():
            serial_port.write(TxData)

def Joint_Ctr_Five_Cmd_Send(Motor_ID, cmd, ctr_val):
    if HWT901_or_PC_Ctr_list.get() == 'PC':
        TxData = []
        TxData.append(frame_head)
        TxData.append(Joint_Motor)
        TxData.append(eval(Motor_Ins_Dict.get(cmd)))
        TxData.append(eval(Motor_ID))
        TxData.append(eval(ctr_val) & 0xFF)
        TxData.append(eval(ctr_val) >> 8 & 0xFF)
        TxData.append(eval(ctr_val) >> 16 & 0xFF)
        TxData.append(eval(ctr_val) >> 24 & 0xFF)
        TxData.append(frame_tail)
        if serial_port.isOpen():
            serial_port.write(TxData)

def tendon_Ctr_Choose(cmd):
    TxData = []
    TxData.append(frame_head)
    TxData.append(tendon_Choose_CMD)
    TxData.append(eval(tendon_Dict.get(cmd)))
    TxData.append(frame_tail)
    if serial_port.isOpen():
        serial_port.write(TxData)

def Motor_Ctr_Host_Choose():
    TxData = []
    TxData.append(frame_head)
    TxData.append(Ctr_Host_Choose)
    if HWT901_or_PC_Ctr_list.get() == 'HWT901':
        TxData.append(0x00)
    elif HWT901_or_PC_Ctr_list.get() == 'PC':
        TxData.append(0x01)
    TxData.append(frame_tail)
    if serial_port.isOpen():
        serial_port.write(TxData)

def Mix_Motor_Ctr(cmd):
    if HWT901_or_PC_Ctr_list.get() == 'PC':
        TxData = []
        TxData.append(frame_head)
        TxData.append(Mix_Motor)
        TxData.append(eval(Motor_Ins_Dict.get(cmd)))
        TxData.append(frame_tail)
        if serial_port.isOpen():
            serial_port.write(TxData)

tk.Label( serial_Motor,
          text = "跟随方:",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 0, column = serial_conf_label_column_step * 0) # 添加串口号标签
tk.Label( serial_Motor,
          text = "关节位置控制ID:",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 1, column = serial_conf_label_column_step * 0) # 添加串口号标签

tk.Label( serial_Motor,
          text = "控制方式",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 1, column = serial_conf_label_column_step * 1) # 添加串口号标签
tk.Label( serial_Motor,
          text = "控制值",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 1, column = serial_conf_label_column_step * 2) # 添加串口号标签
tk.Label( serial_Motor,
          text = "关节单字节控制",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 2, column = serial_conf_label_column_step * 0) # 添加串口号标签
tk.Label( serial_Motor,
          text = "关节五字节控制",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 3, column = serial_conf_label_column_step * 0) # 添加串口号标签
tk.Label( serial_Motor,
          text = "控制值",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 3, column = serial_conf_label_column_step * 1) # 添加串口号标签

tk.Label( serial_Motor,
          text = "脉塔位置控制ID:",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 4, column = serial_conf_label_column_step * 0) # 添加串口号标签

tk.Label( serial_Motor,
          text = "控制方式:",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 4, column = serial_conf_label_column_step * 1) # 添加串口号标签
tk.Label( serial_Motor,
          text = "控制值:",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 4, column = serial_conf_label_column_step * 2) # 添加串口号标签
tk.Label( serial_Motor,
          text = "脉塔单字节控制",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 5, column = serial_conf_label_column_step * 0) # 添加串口号标签

tk.Label( serial_Motor,
          text = "模拟人类行为方式",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 7, column = serial_conf_label_column_step * 0) # 添加串口号标签

tk.Label( serial_Motor,
          text = "肌腱控制：",
          bg="white",
          fg="black").grid(row = serial_conf_label_row_step * 9, column = serial_conf_label_column_step * 0) # 添加串口号标签

#HWT901控制还是PC端控制下拉框
HWT901_or_PC_Ctr_flag = tk.StringVar()  # 波特率字符串
HWT901_or_PC_Ctr_list = ttk.Combobox(serial_Motor,   #父控件
                             width=com_list_width, #下拉列表宽度
                             textvariable=HWT901_or_PC_Ctr_flag, #将显示内容与baudrate绑定
                             state='readonly',
                             )
HWT901_or_PC_Ctr_list['values'] = ( 'HWT901',
                                    'PC')
HWT901_or_PC_Ctr_list.current(1)  # 初始显示
HWT901_or_PC_Ctr_list.grid(row = serial_conf_label_row_step * 0, column = serial_conf_label_column_step * 1 - 1)

#关节电机ID下拉框
Joint_ID = tk.StringVar()  # 波特率字符串
Joint_ID_list = ttk.Combobox(serial_Motor,   #父控件
                             width=com_list_width, #下拉列表宽度
                             textvariable=Joint_ID, #将显示内容与baudrate绑定
                             )
Joint_ID_list['values'] = (0,
                           1,
                           2,
                           3,
                           4,
                           5,
                           6,
                           7,
                           8)
Joint_ID_list.current(1)  # 初始显示
Joint_ID_list.grid(row = serial_conf_label_row_step * 1, column = serial_conf_label_column_step * 0 + 1)

#关节电机控制方式下拉框
Joint_Ctr_t = tk.StringVar()  # 波特率字符串
Joint_Ctr_t_list = ttk.Combobox(serial_Motor,   #父控件
                                width=com_list_width, #下拉列表宽度
                                textvariable=Joint_Ctr_t, #将显示内容与baudrate绑定
                                state='readonly'
                             )
Joint_Ctr_t_list['values'] = ('位置模式',
                              '电流模式',
                              '速度模式')
Joint_Ctr_t_list.current(0)  # 初始显示
Joint_Ctr_t_list.grid(row = serial_conf_label_row_step * 1, column = serial_conf_label_column_step * 1 + 1)

#关节电机控制值下拉框
Joint_Ctr_v = tk.StringVar()
Joint_Ctr_v_list = ttk.Combobox(serial_Motor,   #父控件
                                width=com_list_width, #下拉列表宽度
                                textvariable=Joint_Ctr_v, #将显示内容与baudrate绑定
                             )
Joint_Ctr_v_list['values'] = (0,
                              90,
                              180,
                              270,
                              360)
Joint_Ctr_v_list.current(2)  # 初始显示
Joint_Ctr_v_list.grid(row = serial_conf_label_row_step * 1, column = serial_conf_label_column_step * 2 + 1)

#关节电机单字节控制指令下拉框
Joint_Ctr_Single_Cmd = tk.StringVar()
Joint_Ctr_Single_Cmd_List = ttk.Combobox(serial_Motor,   #父控件
                                width=com_list_width + 4, #下拉列表宽度
                                textvariable=Joint_Ctr_Single_Cmd, #将显示内容与baudrate绑定
                                         )
Joint_Ctr_Single_Cmd_List['value'] = ('Joint_Clear_Err_Command',
                                      'Set_Joint_Stop',
                                      'Get_Pos_Bias',
                                      'Get_Run_State',
                                      'Get_Err_State',
                                      'Get_M_Now_Pos',
                                      'Get_M_Exp_Pos',
                                      )
Joint_Ctr_Single_Cmd_List.current(1)
Joint_Ctr_Single_Cmd_List.grid(row = serial_conf_label_row_step * 2, column = serial_conf_label_column_step * 0 + 1)

#关节电机五字节控制指令下拉框
Joint_Ctr_Five_Cmd = tk.StringVar()
Joint_Ctr_Five_Cmd_List = ttk.Combobox(serial_Motor,   #父控件
                                width=com_list_width + 4, #下拉列表宽度
                                textvariable=Joint_Ctr_Five_Cmd, #将显示内容与baudrate绑定
                                         )
Joint_Ctr_Five_Cmd_List['value'] = ('Joint_Set_Pos_Bias',
                                      )
Joint_Ctr_Five_Cmd_List.current(0)
Joint_Ctr_Five_Cmd_List.grid(row = serial_conf_label_row_step * 3, column = serial_conf_label_column_step * 0 + 1)

#脉塔电机ID下拉框
RMD_ID_t = tk.StringVar()  # 波特率字符串
RMD_ID_t_list = ttk.Combobox(serial_Motor,   #父控件
                             width=com_list_width, #下拉列表宽度
                             textvariable=RMD_ID_t, #将显示内容与baudrate绑定
                             )
RMD_ID_t_list['values'] = (0,
                           1,
                           2,
                           3,
                           4,
                           5,
                           6,
                           7,
                           8)
RMD_ID_t_list.current(0)  # 初始显示
RMD_ID_t_list.grid(row = serial_conf_label_row_step * 4, column = serial_conf_label_column_step * 0 + 1)

#脉塔电机控制方式下拉框
RMD_Ctr_t = tk.StringVar()  # 波特率字符串
RMD_Ctr_t_list = ttk.Combobox(serial_Motor,   #父控件
                             width=com_list_width, #下拉列表宽度
                             textvariable=RMD_Ctr_t, #将显示内容与baudrate绑定
                             state='readonly'
                             )
RMD_Ctr_t_list['values'] = ('单圈模式',
                            '多圈模式')
RMD_Ctr_t_list.current(0)  # 初始显示
RMD_Ctr_t_list.grid(row = serial_conf_label_row_step * 4, column = serial_conf_label_column_step * 1 + 1)

#脉塔电机控制值下拉框
RMD_Ctr_v = tk.StringVar()  # 波特率字符串
RMD_Ctr_v_list = ttk.Combobox(serial_Motor,   #父控件
                             width=com_list_width, #下拉列表宽度
                             textvariable=RMD_Ctr_v, #将显示内容与baudrate绑定
                             )
RMD_Ctr_v_list['values'] = (  0,
                              90,
                              180,
                              270,
                              360)
RMD_Ctr_v_list.current(2)  # 初始显示
RMD_Ctr_v_list.grid(row = serial_conf_label_row_step * 4, column = serial_conf_label_column_step * 2 + 1)

#脉塔电机单字节指令控制下拉框
RMD_Ctr_Single_Cmd = tk.StringVar()
RMD_Ctr_Single_Cmd_List = ttk.Combobox(serial_Motor,   #父控件
                                width=com_list_width + 4, #下拉列表宽度
                                textvariable=RMD_Ctr_Single_Cmd, #将显示内容与baudrate绑定
                                         )
RMD_Ctr_Single_Cmd_List['value'] = ('RMD_Stop_Motor_Command',
                                    'RMD_Pause_Motor_Command',
                                    'RMD_Run_Motor_Command',
                                      )
RMD_Ctr_Single_Cmd_List.current(0)
RMD_Ctr_Single_Cmd_List.grid(row = serial_conf_label_row_step * 5, column = serial_conf_label_column_step * 0 + 1)


tk.Button( serial_Motor,
           text = "发送 ->主控", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Motor_Ctr_Host_Choose() , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 0, column = serial_conf_label_column_step * 1)

tk.Button( serial_Motor,
           text = "发送 -> 关节电机", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Joint_Motor_Pos_Ctr(Joint_ID_list.get(), Joint_Ctr_v_list.get()) , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 1, column = serial_conf_label_column_step * 3)

tk.Button( serial_Motor,
           text = "发送->单字控制", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Joint_Ctr_Single_Cmd_Send(Joint_ID_list.get(), Joint_Ctr_Single_Cmd_List.get()) , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 2, column = serial_conf_label_column_step * 3)

tk.Button( serial_Motor,
           text = "发送->五字控制", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Joint_Ctr_Five_Cmd_Send(Joint_ID_list.get(), Joint_Ctr_Five_Cmd_List.get(), joint_fk_set_entry.get()) , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 3, column = serial_conf_label_column_step * 3)

tk.Button( serial_Motor,
           text = "发送 -> 脉塔电机", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:RMD_Motor_Single_Pos_Ctr(RMD_ID_t_list.get(), RMD_Ctr_v_list.get()) , #按下时执行的函数命令
          ).grid(row = serial_conf_label_row_step * 4, column = serial_conf_label_column_step * 3)

tk.Button( serial_Motor,
           text = "发送->单字控制", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:RMD_Motor_ins_Send(RMD_ID_t_list.get(), RMD_Ctr_Single_Cmd_List.get()) , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 5, column = serial_conf_label_column_step * 3)

tk.Button( serial_Motor,
           text = "复位", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Reset_Motor') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0)

tk.Button( serial_Motor,
           text = "向前90°", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Forward_90_Command') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0 + 1)

tk.Button( serial_Motor,
           text = "向右90°", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Turn_Right_90_Command') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0 + 2)

tk.Button( serial_Motor,
           text = "向斜上方90°", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Inclined_Top_90_Command') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0 + 3)

tk.Button( serial_Motor,
           text = "巡航°", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Wave_Hand') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0 + 4)
tk.Button( serial_Motor,
           text = "画大三角°", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Draw_Triangular') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0 + 5)

tk.Button( serial_Motor,
           text = "画圈°", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Draw_circle') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0 + 6)

tk.Button( serial_Motor,
           text = "模拟写黑板°", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:Mix_Motor_Ctr('Write_on_the_blackboard') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 8, column = serial_conf_label_column_step * 0 + 7)

tk.Button( serial_Motor,
           text = "确定", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:tendon_Ctr_Choose('tendon_control_Command') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 9, column = serial_conf_label_column_step * 0 + 1)
tk.Button( serial_Motor,
           text = "取消", # 按键名称
           activebackground="white", # 按键按下时的背景色
           activeforeground="black",# 按键按下时的字体背景色
           bg="white", # 按键背景色
           fg="black", # 按键前景色
           command = lambda:tendon_Ctr_Choose('tendon_abandon_Command') , #按下时执行的函数命令 -- get得到字符串类型
          ).grid(row = serial_conf_label_row_step * 9, column = serial_conf_label_column_step * 1 + 0)

#单字节关节电机反馈值
joint_fk_show = tk.StringVar()
joint_fk_show_entry = tk.Entry(serial_Motor, width=12, textvariable=joint_fk_show)
joint_fk_show_entry.insert(0, 'NULL')
joint_fk_show_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
joint_fk_show_entry.grid(row = serial_conf_label_row_step * 2, column = serial_conf_label_column_step * 3 + 1)

#五字节关节电机设置值
joint_fk_set = tk.StringVar()
joint_fk_set_entry = tk.Entry(serial_Motor, width=12, textvariable=joint_fk_set)
joint_fk_set_entry.insert(0, '0')
joint_fk_set_entry.configure(state='normal', disabledbackground = 'white',disabledforeground = 'black')
joint_fk_set_entry.grid(row = serial_conf_label_row_step * 3, column = serial_conf_label_column_step * 1 + 1)

#五字节关节电机反馈值
joint_ffk_show = tk.StringVar()
joint_ffk_show_entry = tk.Entry(serial_Motor, width=12, textvariable=joint_ffk_show)
joint_ffk_show_entry.insert(0, 'NULL')
joint_ffk_show_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
joint_ffk_show_entry.grid(row = serial_conf_label_row_step * 3, column = serial_conf_label_column_step * 3 + 1)

#脉塔电机反馈值
RMD_fk_show = tk.StringVar()
RMD_fk_show_entry = tk.Entry(serial_Motor, width=12, textvariable=RMD_fk_show)
RMD_fk_show_entry.insert(0, 'NULL')
RMD_fk_show_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
RMD_fk_show_entry.grid(row = serial_conf_label_row_step * 5, column = serial_conf_label_column_step * 3 + 1)

# ##########################################################写好的Motor函数区域############################################################
# ############## 脉塔电机1 停止测试 ####################
# tk.Button(serial_Motor,
#           text="脉塔电机 停止",  # 按键名称
#           activebackground="white",  # 按键按下时的背景色
#           activeforeground="black",  # 按键按下时的字体前景色
#           bg="white",  # 按键背景色
#           fg="black",  # 按键前景色
#           command=lambda: RMD_Motor_ins_Send(RMD_Motor, RMD_ID, Motor_Ins_Dict.get('RMD_Stop_Motor_Command')),  # 传函带参特殊处理
#           ).place(x=Motor_X_Init + Motor_X_Step * 0, y=Motor_Y_Init + Motor_Y_Step * 2.5, width=100, height=30)
# ############## 脉塔电机1 暂停测试 ####################
# tk.Button(serial_Motor,
#           text="脉塔电机  暂停",  # 按键名称
#           activebackground="white",  # 按键按下时的背景色
#           activeforeground="black",  # 按键按下时的字体前景色
#           bg="white",  # 按键背景色
#           fg="black",  # 按键前景色
#           command=lambda: RMD_Motor_ins_Send(RMD_Motor, RMD_ID, Motor_Ins_Dict.get('RMD_Pause_Motor_Command')),
#           ).place(x=Motor_X_Init + Motor_X_Step * 1, y=Motor_Y_Init + Motor_Y_Step * 2.5, width=100, height=30)
# ##############  脉塔电机1 运行测试 ####################
# tk.Button(serial_Motor,
#           text="脉塔电机 运行",  # 按键名称
#           activebackground="white",  # 按键按下时的背景色
#           activeforeground="black",  # 按键按下时的字体前景色
#           bg="white",  # 按键背景色
#           fg="black",  # 按键前景色
#           command=lambda: RMD_Motor_ins_Send(RMD_Motor, RMD_ID, Motor_Ins_Dict.get('RMD_Run_Motor_Command')),
#           ).place(x=Motor_X_Init + Motor_X_Step * 2, y=Motor_Y_Init + Motor_Y_Step * 2.5, width=100, height=30)

####################################################################
####################################################################
####################################################################
####################### 接收数据区域(原始数据) #########################
####################################################################
####################################################################
####################################################################

serial_rev_ori = tk.LabelFrame(tk_window,  # 区域所在窗口
                           text="接收数据区域(原始数据)",  # 这片区域的名称
                           bg="white",  # 区域背景色
                           fg="black",  # 前景色
                           padx=10,     # 与其他组件空余的距离
                           pady=10
                           )
serial_rev_ori.place(x=serial_place_x + 750, y=serial_place_y,
                 width=serial_place_width, height=serial_place_height + 260
                 )

rev_buffer_scr = scrolledtext.ScrolledText(serial_rev_ori, bg='white', width=80, height=30, highlightcolor='black',
                        highlightthickness=1)  # 注意框并非越大越好 要在父控件以内 否则会出现隐藏情况
rev_buffer_scr.insert(END, '')
rev_buffer_scr.place(x=0, y=5)

rev_state = tk.IntVar()
r_state = tk.Checkbutton(serial_rev_ori, text = "hex接收", variable = rev_state, bg="white",  fg="black")
r_state.select()
r_state.place(x=600, y=15, width=100, height=30)

tk.Button(serial_rev_ori,
          text="清除接收区",  # 按键名称
          activebackground="white",  # 按键按下时的背景色
          activeforeground="black",  # 按键按下时的字体前景色
          bg="white",  # 按键背景色
          fg="black",  # 按键前景色
          command=lambda: rev_buffer_scr.delete(1.0, 'end'),
          ).place(x=600, y=360, width=100, height=30)


####################################################################
####################################################################
####################################################################
####################### 接收数据区域(固定数据) #########################
####################################################################
####################################################################
####################################################################


####################################################################
#########################下位机欧拉角数据接收###########################
####################################################################
serial_rev_fix = tk.LabelFrame(tk_window,  # 区域所在窗口
                           text="接收数据区域(固定数据)",  # 这片区域的名称
                           bg="white",  # 区域背景色
                           fg="black",  # 前景色
                           padx=10,     # 与其他组件空余的距离
                           pady=10
                           )
serial_rev_fix.place(x=serial_place_x + 750, y=serial_place_y + 360,
                 width=serial_place_width, height=serial_place_height + 500
                 )

tk.Label(serial_rev_fix, text = 'HWT901-TTL数据', bg="white",
          fg="black").grid(column = 0 , row = 0)

roll = tk.StringVar()
yaw = tk.StringVar()
pitch = tk.StringVar()
tk.Label(serial_rev_fix, text = 'roll', bg="white",
          fg="black").grid(column = 0, row = 1)
roll_entry = tk.Entry(serial_rev_fix, textvariable=roll)
roll_entry.insert(0, '0.0')
roll_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
roll_entry.grid(column = 0, row = 2, padx = 10)

tk.Label(serial_rev_fix, text = 'yaw', bg="white",
          fg="black").grid(column = 1, row = 1)
yaw_entry = tk.Entry(serial_rev_fix, textvariable=yaw)
yaw_entry.insert(0, '0.0')
yaw_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
yaw_entry.grid(column = 1, row = 2, padx = 10)

tk.Label(serial_rev_fix, text = 'pitch', bg="white",
          fg="black").grid(column = 2, row = 1)
pitch_entry = tk.Entry(serial_rev_fix, textvariable=pitch)
pitch_entry.insert(0, '0.0')
pitch_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
pitch_entry.grid(column = 2, row = 2, padx = 10)

####################################################################
#########################下位机加速度数据接收###########################
####################################################################
acc_x = tk.StringVar()
acc_y = tk.StringVar()
acc_z = tk.StringVar()
tk.Label(serial_rev_fix, text = 'acc_x', bg="white",
          fg="black").grid(column = 0, row = 4)
acc_x_entry = tk.Entry(serial_rev_fix, textvariable=acc_x)
acc_x_entry.insert(0, '0.0')
acc_x_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
acc_x_entry.grid(column = 0, row = 5, padx = 10)

tk.Label(serial_rev_fix, text = 'acc_y', bg="white",
          fg="black").grid(column = 1, row = 4)
acc_y_entry = tk.Entry(serial_rev_fix, textvariable=acc_y)
acc_y_entry.insert(0, '0.0')
acc_y_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
acc_y_entry.grid(column = 1, row = 5, padx = 10)

tk.Label(serial_rev_fix, text = 'acc_z', bg="white",
          fg="black").grid(column = 2, row = 4)
acc_z_entry = tk.Entry(serial_rev_fix, textvariable=acc_z)
acc_z_entry.insert(0, '0.0')
acc_z_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
acc_z_entry.grid(column = 2, row = 5, padx = 10)

####################################################################
#########################下位机陀螺仪数据接收###########################
####################################################################
gyro_x = tk.StringVar()
gyro_y = tk.StringVar()
gyro_z = tk.StringVar()
tk.Label(serial_rev_fix, text = 'gyro_x', bg="white",
          fg="black").grid(column = 0, row = 7)
gyro_x_entry = tk.Entry(serial_rev_fix, textvariable=gyro_x)
gyro_x_entry.insert(0, '0.0')
gyro_x_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
gyro_x_entry.grid(column = 0, row = 8, padx = 10)

tk.Label(serial_rev_fix, text = 'gyro_y', bg="white",
          fg="black").grid(column = 1, row = 7)
gyro_y_entry = tk.Entry(serial_rev_fix, textvariable=gyro_y)
gyro_y_entry.insert(0, '0.0')
gyro_y_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
gyro_y_entry.grid(column = 1, row = 8, padx = 10)

tk.Label(serial_rev_fix, text = 'gyro_z', bg="white",
          fg="black").grid(column = 2, row = 7)
gyro_z_entry = tk.Entry(serial_rev_fix, textvariable=gyro_z)
gyro_z_entry.insert(0, '0.0')
gyro_z_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
gyro_z_entry.grid(column = 2, row = 8, padx = 10)


####################################################################
##########################polhemux数据接收############################
####################################################################
tk.Label(serial_rev_fix, text = '', bg="white",
          fg="black").grid(column = 0 , row = 9)
tk.Label(serial_rev_fix, text = 'polhemux - sensor数据', bg="white",
          fg="black").grid(column = 0 , row = 10)

polhemux_sensor1_x = tk.StringVar()
polhemux_sensor1_y = tk.StringVar()
polhemux_sensor1_z = tk.StringVar()
polhemux_sensor1_yaw = tk.StringVar()
polhemux_sensor1_pitch = tk.StringVar()
polhemux_sensor1_roll = tk.StringVar()

tk.Label(serial_rev_fix, text = 'sensor1_x', bg="white",
          fg="black").grid(column = 0, row = 11)
polhemux_sensor1_x_entry = tk.Entry(serial_rev_fix, textvariable=polhemux_sensor1_x)
polhemux_sensor1_x_entry.insert(0, '0.0')
polhemux_sensor1_x_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
polhemux_sensor1_x_entry.grid(column = 0, row = 12, padx = 10)

tk.Label(serial_rev_fix, text = 'sensor1_y', bg="white",
          fg="black").grid(column = 1, row = 11)
polhemux_sensor1_y_entry = tk.Entry(serial_rev_fix, textvariable=polhemux_sensor1_y)
polhemux_sensor1_y_entry.insert(0, '0.0')
polhemux_sensor1_y_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
polhemux_sensor1_y_entry.grid(column = 1, row = 12, padx = 10)

tk.Label(serial_rev_fix, text = 'sensor1_z', bg="white",
          fg="black").grid(column = 2, row = 11)
polhemux_sensor1_z_entry = tk.Entry(serial_rev_fix, textvariable=polhemux_sensor1_z)
polhemux_sensor1_z_entry.insert(0, '0.0')
polhemux_sensor1_z_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
polhemux_sensor1_z_entry.grid(column = 2, row = 12, padx = 10)

tk.Label(serial_rev_fix, text = 'sensor1_yaw', bg="white",
          fg="black").grid(column = 0, row = 13)
polhemux_sensor1_yaw_entry = tk.Entry(serial_rev_fix, textvariable=polhemux_sensor1_yaw)
polhemux_sensor1_yaw_entry.insert(0, '0.0')
polhemux_sensor1_yaw_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
polhemux_sensor1_yaw_entry.grid(column = 0, row = 14, padx = 10)

tk.Label(serial_rev_fix, text = 'sensor1_pitch', bg="white",
          fg="black").grid(column = 1, row = 13)
polhemux_sensor1_pitch_entry = tk.Entry(serial_rev_fix, textvariable=polhemux_sensor1_pitch)
polhemux_sensor1_pitch_entry.insert(0, '0.0')
polhemux_sensor1_pitch_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
polhemux_sensor1_pitch_entry.grid(column = 1, row = 14, padx = 10)

tk.Label(serial_rev_fix, text = 'sensor1_roll', bg="white",
          fg="black").grid(column = 2, row = 13)
polhemux_sensor1_roll_entry = tk.Entry(serial_rev_fix, textvariable=polhemux_sensor1_roll)
polhemux_sensor1_roll_entry.insert(0, '0.0')
polhemux_sensor1_roll_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
polhemux_sensor1_roll_entry.grid(column = 2, row = 14, padx = 10)


####################################################################
##########################电机角度反馈数据接收############################
####################################################################
tk.Label(serial_rev_fix, text = '', bg="white",
          fg="black").grid(column = 0 , row = 15)
tk.Label(serial_rev_fix, text = '电机角度实时反馈', bg="white",
          fg="black").grid(column = 0 , row = 16)

Joint_Motor_ID1 = tk.StringVar()
Joint_Motor_ID2 = tk.StringVar()

tk.Label(serial_rev_fix, text = '关节电机ID1', bg="white",
          fg="black").grid(column = 0, row = 17)
Joint_Motor_ID1_entry = tk.Entry(serial_rev_fix, textvariable=Joint_Motor_ID1)
Joint_Motor_ID1_entry.insert(0, '0.0')
Joint_Motor_ID1_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
Joint_Motor_ID1_entry.grid(column = 0, row = 18, padx = 10)

tk.Label(serial_rev_fix, text = '关节电机ID2', bg="white",
          fg="black").grid(column = 1, row = 17)
Joint_Motor_ID2_entry = tk.Entry(serial_rev_fix, textvariable=Joint_Motor_ID2)
Joint_Motor_ID2_entry.insert(0, '0.0')
Joint_Motor_ID2_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
Joint_Motor_ID2_entry.grid(column = 1, row = 18, padx = 10)

Motor_record_state = tk.IntVar()
Motor_record_state_check_box = tk.Checkbutton(serial_rev_fix, text = "数据记录", variable = Motor_record_state, bg="white",  fg="black")
# Motor_record_state_check_box.select()
Motor_record_state_check_box.grid(column = 2, row = 18, padx = 10)

####################################################################
##########################比例阀反馈数据接收############################
####################################################################
tk.Label(serial_rev_fix, text = '', bg="white",
          fg="black").grid(column = 0 , row = 19)
tk.Label(serial_rev_fix, text = '比例阀气压实时反馈', bg="white",
          fg="black").grid(column = 0 , row = 20)

ppv_1 = tk.StringVar()
ppv_2 = tk.StringVar()
ppv_3 = tk.StringVar()
ppv_4 = tk.StringVar()
ppv_5 = tk.StringVar()
ppv_6 = tk.StringVar()
ppv_7 = tk.StringVar()

tk.Label(serial_rev_fix, text = '比例阀1号', bg="white",
          fg="black").grid(column = 0, row = 21)
ppv_1_entry = tk.Entry(serial_rev_fix, textvariable=ppv_1)
ppv_1_entry.insert(0, '0.0')
ppv_1_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
ppv_1_entry.grid(column = 0, row = 22, padx = 10)

tk.Label(serial_rev_fix, text = '比例阀2号', bg="white",
          fg="black").grid(column = 1, row = 21)
ppv_2_entry = tk.Entry(serial_rev_fix, textvariable=ppv_2)
ppv_2_entry.insert(0, '0.0')
ppv_2_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
ppv_2_entry.grid(column = 1, row = 22, padx = 10)

tk.Label(serial_rev_fix, text = '比例阀3号', bg="white",
          fg="black").grid(column = 2, row = 21)
ppv_3_entry = tk.Entry(serial_rev_fix, textvariable=ppv_3)
ppv_3_entry.insert(0, '0.0')
ppv_3_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
ppv_3_entry.grid(column = 2, row = 22, padx = 10)

tk.Label(serial_rev_fix, text = '比例阀4号', bg="white",
          fg="black").grid(column = 0, row = 23)
ppv_4_entry = tk.Entry(serial_rev_fix, textvariable=ppv_4)
ppv_4_entry.insert(0, '0.0')
ppv_4_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
ppv_4_entry.grid(column = 0, row = 24, padx = 10)

tk.Label(serial_rev_fix, text = '比例阀5号', bg="white",
          fg="black").grid(column = 1, row = 23)
ppv_5_entry = tk.Entry(serial_rev_fix, textvariable=ppv_5)
ppv_5_entry.insert(0, '0.0')
ppv_5_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
ppv_5_entry.grid(column = 1, row = 24, padx = 10)

tk.Label(serial_rev_fix, text = '比例阀6号', bg="white",
          fg="black").grid(column = 2, row = 23)
ppv_6_entry = tk.Entry(serial_rev_fix, textvariable=ppv_6)
ppv_6_entry.insert(0, '0.0')
ppv_6_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
ppv_6_entry.grid(column = 2, row = 24, padx = 10)

tk.Label(serial_rev_fix, text = '比例阀7号', bg="white",
          fg="black").grid(column = 3, row = 23)
ppv_7_entry = tk.Entry(serial_rev_fix, textvariable=ppv_7)
ppv_7_entry.insert(0, '0.0')
ppv_7_entry.configure(state='disable', disabledbackground = 'white',disabledforeground = 'black')
ppv_7_entry.grid(column = 3, row = 24, padx = 10)

if __name__ == '__main__':
    tk_window.after(100, AutoFind_Serial.IMU_wrist_elbow_ope())
    tk_window.mainloop()


